﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Douyu.SDK
{
    /// <summary>
    /// STT序列化工具
    /// </summary>
    /// <remarks>
    /// 1. 键Key和值Value采用"@="进行分隔
    /// 2. 数组采用"/"分隔
    /// 3. 转义符;
    ///    @ -> @A,
    ///    / -> @S
    ///    坑2: 缺少 "=" 的转义符
    /// </remarks>
    public static class STTSerializer
    {
        /// <summary>
        /// 将消息类序列化成消息串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Message"></param>
        /// <returns></returns>
        public static string Serialize<T>(T Message)
            where T : BaseMessage
        {
            return Serialize(Message.Datas);
        }

        /// <summary>
        /// 序列化消息
        /// </summary>
        /// <param name="Msg"></param>
        /// <returns></returns>
        public static string Serialize(Dictionary<string, object> Msg)
        {
            var ret = new StringBuilder();
            try
            {
                foreach (var k in Msg.Keys)
                {
                    var v = Msg[k];
                    var v2 = string.Empty;
                    if (v is Dictionary<string, object>)
                    {
                        v2 = Serialize(v as Dictionary<string, object>)
                            .ParamEncode();
                    }
                    else
                    {
                        v2 = v.ToString().ParamEncode();
                    }
                    ret.Append(string.Concat(
                        k.ToString(), "@=", v2, "/"
                    ));
                }
            }
            catch
            {
            }
            return ret.ToString();
        }

        /// <summary>
        /// 转义符
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string ParamEncode(this string str)
        {
            var ret = str
                .Replace("@", "@A")
                .Replace("/", "@S");
            return ret;
        }

        /// <summary>
        /// 反转义符
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string ParamDecode(this string str)
        {
            var ret = str
                .Replace("@A", "@")
                .Replace("@S", "/");
            return ret;
        }

        /// <summary>
        /// 将消息体反序列化成消息类
        /// </summary>
        /// <typeparam name="T">要转换的消息类</typeparam>
        /// <param name="msg">消息体</param>
        /// <returns></returns>
        public static T Deserialize<T>(T msg, string MessageBody)
            where T : BaseMessage
        {
            var ret = msg;
            msg.MessageBody = MessageBody;
            msg.setDatas(Deserialize(MessageBody));
            return ret;
        }

        /// <summary>
        /// 反序列化
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public static Dictionary<string, object> Deserialize(string msg)
        {
            var ret = new Dictionary<string, object>();
            var items = msg.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
            var index = 0;
            foreach (var item in items)
            {
                var sp = item.Split(new string[] { "@=" }, 2, StringSplitOptions.None);
                var k = sp.Length > 0 ? sp[0] : string.Empty;
                if (k.Length <= 0) continue;

                var v = string.Empty;
                if(sp.Length > 1)
                {
                    v = sp[1];
                }
                else
                {
                    //数组情况
                    v = k;
                    k = (index++).ToString();
                }
                if (v.Contains("@A"))
                {
                    //含有子项
                    v = v.ParamDecode();
                    var v2 = Deserialize(v);
                    ret.Add(k, v2);
                }
                else
                {
                    v = v.ParamDecode();
                    ret.Add(k, v);
                }
            }
            return ret;
        }

    }

}
